--luacheck: ignore describe it

local rapidjson = require('rapidjson')

local function validate(schema, json)
	local validator = rapidjson.SchemaValidator(schema)
	local d = rapidjson.Document()
	d:parse(json)
	return d:validate(validator)
end

describe('rapidjson.SchemaDocument', function()
	describe('construct from valid args', function()
		it('no args', function()
			assert.are.equals('userdata', type(rapidjson.SchemaDocument()))
		end)
		it('empty string', function()
			assert.are.equals('userdata', type(rapidjson.SchemaDocument('')))
		end)
		it('empty json string', function()
			local sd = rapidjson.SchemaDocument('{ }')
			assert.are.equals('userdata', type(sd))
		end)
		it('schema document json string', function()
			local sd = rapidjson.SchemaDocument('{ "type": ["number", "string"] }')
			assert.are.equals('userdata', type(sd))
		end)
		it('a rapidjson.Document object', function()
			local doc = rapidjson.Document('{ "type": ["number", "string"] }')
			local sd = rapidjson.SchemaDocument(doc)
			assert.are.equals('userdata', type(sd))
		end)
		it('a lua table', function()
			local sd = rapidjson.SchemaDocument({ type = {"number", "string"} })
			assert.are.equals('userdata', type(sd))
		end)
	end)
	describe('raise error when arg is', function()
		it('nil', function()
			assert.has.error(function()
				rapidjson.SchemaDocument(nil)
			end)
		end)
		it('number', function()
			assert.has.error(function()
				rapidjson.SchemaDocument(10)
			end)
		end)
		it('bad userdata', function()
			assert.has.error(function()
				rapidjson.SchemaDocument(io.output)
			end)
		end)
		it('arg is function', function()
			assert.has.error(function()
				rapidjson.SchemaDocument(function() end)
			end)
		end)
	end)
end)


describe('rapidjson.SchemaValidator', function()

	describe('rapidjson.SchemaValidator()', function()
		describe('creates a SchemaValidator', function()
			it('form a empty SchemaDocument object', function()
				local s = rapidjson.SchemaDocument()
				local validator = rapidjson.SchemaValidator(s)
				assert.are.equals('userdata', type(validator))
			end)
			it('from a normal SchemaDocument', function()
				local s = rapidjson.SchemaDocument('{ "type": ["number", "string"] }')
				local validator = rapidjson.SchemaValidator(s)
				assert.are.equals('userdata', type(validator))
			end)
		end)
		describe('raise error', function()
			it('in other case', function()
				assert.has.error(function()
					rapidjson.SchemaValidator()
				end)
				assert.has.error(function()
					rapidjson.SchemaValidator(1)
				end)
				assert.has.error(function()
					rapidjson.SchemaValidator(false)
				end)
				assert.has.error(function()
					rapidjson.SchemaValidator(io.output)
				end)
				assert.has.error(function()
					rapidjson.SchemaValidator(function() end)
				end)
			end)
		end)
	end)
	describe(':validate() validates JSON Document', function()
		local schema, validator
		setup(function()
			schema = rapidjson.SchemaDocument('{ "type": ["number", "string"] }')
		end)
		before_each(function()
			validator = rapidjson.SchemaValidator(schema)
		end)
		describe('when doc is valid', function()
			it('returns true', function()
				local n = rapidjson.Document('42')
				assert.is_true(validator:validate(n))
				local s = rapidjson.Document('"this is a json string"')
				assert.is_true(validator:validate(s))
			end)
		end)
		describe('when doc is invalid', function()
			it('returns false plus a error message', function()
				local invalid = rapidjson.Document('{"a": "b"}')
				local ok, err = validator:validate(invalid)
				assert.is_false(ok)
				assert.is_not_nil(ok)
				assert.are.equals('string', type(err))
				assert.are.equals('invalid "type" in docuement at pointer "#"', err)
			end)
		end)
		describe('restes validator status internally', function()
			it('so that can validate mulitple docuement', function()
				local n = rapidjson.Document('42')
				local invalid = rapidjson.Document('{"a": "b"}')
				assert.is_true(validator:validate(n))
				assert.is_false((validator:validate(invalid)))
				assert.is_true(validator:validate(n))
				assert.is_false((validator:validate(invalid)))
			end)
		end)
	end)
end)
